home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / emac16as.arc / MINTSCAN.ASM < prev    next >
Assembly Source File  |  1990-04-01  |  16KB  |  605 lines

  1. ;History:143,1
  2. ;Tue Dec 19 22:40:56 1989 Add an ifdef for 'timing' to disable the profiling code.
  3. ;Sun Nov 12 22:51:36 1989 add profiling to the code.
  4. ;Thu Sep 14 23:26:52 1989 Add make_active and remove return_arg_active.
  5. ;12-12-87 13:41:44 bum a lot of instructions out of scan_loop.
  6. ;12-07-87 20:09:39 add store_debug
  7. ;11-23-87 22:20:47 use scan_copy as the base of scan_xlat_table.
  8.     page    ,132
  9.  
  10.     .xlist
  11.     include mint.def
  12.     .list
  13.  
  14. HT    equ    9
  15. LF    equ    10
  16. CR    equ    13
  17.  
  18. code    segment    byte public
  19. code    ends
  20.  
  21. data    segment byte public
  22. data    ends
  23.  
  24. bufseg    segment public
  25.     public    prev_buffer, next_buffer, toptop, topbot, bottop, botbot, new_size
  26.     define_buffer
  27. bufseg    ends
  28.  
  29. data    segment byte public
  30.     public    data_bottop, data_topbot, data_botbot
  31.     define_buffer    data_
  32. data    ends
  33.  
  34. data    segment byte public
  35.  
  36. comment /******************************************************************
  37.  
  38. Introduction:
  39.  
  40.     The MINT data structures are laid out in memory as given below.
  41. First are the variables, followed by the neutral string.  Next is the
  42. block of free memory.
  43.  
  44.     variables, neutral string ... free memory ... neutral string.
  45.  
  46. The neutral string:
  47.  
  48.     The neutral string consists of a list of arguments.  Each argument
  49. begins with header which might be laid out as so in Pascal:
  50.     arg_header = record
  51.      marker : (active_marker, neutral_marker, comma_marker);
  52.      previous : ^arg_header;
  53.     end;
  54.  
  55. The pointer, previous, points to the previous arg_header. The last one in the
  56. list has a nil pointer.  This will always be the #(ps) which is the outermost
  57. function to be executed.
  58.  
  59. The neutral string during function execution:
  60.  
  61.     Since we are interested in counting arguments from left to right,
  62. not right to left, we need to reverse the pointers so that they point
  63. from the first argument, to the second argument, to the third argument,
  64. etc.  At this point, [fbgn] points to the first argument (the name of the
  65. funciton), and [fend] points past the last argument.  To make argument
  66. fetching more efficient, the last argument is followed by a null argument
  67. which points to itself.  This causes missing arguments to be fetched as
  68. nulls, in according to the definition of the language.
  69.     Functions which return a value will build that value at either
  70. [fbgn]-1 or [fend]-2, depending on whether or not they need to refer to
  71. arguments supplied to the function.  In general, single argument functions
  72. will use [fbgn]-1, and multiple argument functions will use [fend]-2.
  73.  
  74. Neutral function results will eventually be moved to [fbgn]-1.
  75.  
  76. The active string:
  77.  
  78.     The active string consists of a string of ASCII characters which
  79. have not yet been scanned.  Typically, only ASCII characters appear here,
  80. although any eight bit value may occur.
  81.  
  82. The active string during function execution:
  83.  
  84.     [actptr] points to the end of the active string.  Active function
  85. results are built as described above and then moved to the left of [actptr].
  86. Actptr is then adjusted to point to the result just moved in.  Primitives
  87. check for memory overflow by comparing [fend] to [actptr].  If they come
  88. closer than some magic constant, then the 'No Memory' error is given
  89. and the idling string is reloaded.
  90.  
  91.  
  92. **************************************************************************/
  93.  
  94.  
  95.     public    trace
  96.     public    next_ids
  97.     extrn    standard_ids: byte
  98.     public    fbgn, fend
  99.     extrn    lomem: byte
  100.  
  101. trace    db    0        ;trace is initially off.
  102. next_ids    dw    standard_ids
  103. fbgn    dw    ?
  104. fend    dw    ?
  105. fcn_save    db    ?
  106. prev_fcn    dw    ?
  107.  
  108. ;some constant definitions
  109.  
  110. ;the _mark constants mark where a particular type of string occurs in
  111. ; the linked list.
  112.  
  113. comma_marker    equ    0    ;comma_marker must not have function_marker_mask set!
  114. active_marker    equ    1    ;active_marker must have function_marker_mask set!
  115. neutral_marker    equ    3    ;neutral_marker must have function_marker_mask set!
  116. function_marker_mask    equ    1
  117.  
  118. entry    macro    char, adr
  119.     org    (offset scan_xlat_table)+char
  120.     db    (offset adr) - (offset scan_copy)
  121.     endm
  122.  
  123.     db    0
  124. scan_xlat_table    db    256 dup (0)
  125. ;first, fill up the table with 'copy'
  126. ;next, put the proper addresses in the right spots,
  127.     entry    HT,scan_ignore
  128.     entry    CR,scan_ignore
  129.     entry    LF,scan_ignore
  130.     entry    '#',scan_sharp
  131.     entry    '(',scan_lpar
  132.     entry    ')',scan_rpar
  133.     entry    ',',scan_comma
  134. ;finally, go to the end of the table.
  135.     org    (offset scan_xlat_table)+(size scan_xlat_table)
  136.  
  137.     purge    entry
  138.  
  139.     extrn    function_name_table: word
  140.     extrn    function_name_length: abs
  141.     extrn    function_address: word
  142.  
  143.   if timing
  144.     extrn    counting: byte
  145.  
  146.     public    counts
  147. counts    dw    100 dup(0)
  148.  
  149.     public    times
  150. times    dw    100 dup(0)
  151.   endif
  152.  
  153. nomem_prompt        db    'No memory!',0
  154. fatal_prompt        db    'No disk in drive or door open!',0
  155. protected_prompt    db    'Disk is write protected!',0
  156.  
  157.     extrn    stackp: byte
  158.  
  159. buffers_bad_msg    db    'Buffers corrupted, reboot:','$'
  160. buffers_be_msg    db    'xx will say Buffers corrupted, reboot:','$'
  161.  
  162.  
  163. data    ends
  164.  
  165.  
  166. code    segment byte public
  167.  
  168.     assume    cs:code, ds:data, es:data
  169.  
  170. comment /*******************************************************************
  171.     The following is the MINT scan loop.  This loop must be as fast as
  172. possible because it is executed the most often.   As a consequence, the
  173. code is quite unstructured.  However, the code follows the algorithm given in
  174. the MINT language definition document.
  175.     During scan, si -> (points to) the active string, di -> the
  176. neutral string, dx -> previous argument, and bp -> end of active string.
  177.     As we scan a character, we must branch to certain routines on certain
  178. characters.  To make best use of the 8086 instruction set, we have set up a
  179. translate table.  Therefore, the translate table, scan_xlat_table, contains an
  180. offset from the beginning of the scan loop.
  181.  
  182.     When the scan loop has finally found a function to be executed,
  183. a jump is performed to that primitive (unknown primitives cause jump to dflt).
  184. When the primitive is finished, it jumps (with the exception of hl) to one of
  185. the 'return_???' functions.  Each of the return_??? routines puts the returned
  186. value in the proper place in the proper string (active or neutral), and jumps
  187. back to scan.
  188.     The scan loop is repeatedly executed until there are no more functions
  189. to be executed, or the available memory has been exhausted.
  190. *****************************************************************************/
  191.  
  192. scan_copy:            ;come here to copy a char from active to neutral
  193. scan_loop:
  194.     lodsb            ;movsb loses because it doesn't load AL.
  195.     stosb
  196.     xlat            ;al was char, is now offset
  197.     jmp    ax
  198.  
  199. scan_ignore:            ;come here to throw a char away from active.
  200.     dec    di
  201.     jmp    scan_loop
  202.  
  203. scan_lpar:
  204.     dec    di            ;uncopy the '('
  205.     mov    cx,1
  206. scan_lpar_1:
  207.     lodsb            ;can't use movsb, because it doesn't load al
  208.     stosb
  209.     cmp    al,'('
  210.     je    scan_lpar_2
  211.     cmp    al,')'
  212.     jne    scan_lpar_1
  213.     cmp    si,bp            ;was this our sentinel?
  214.     je    init_ids_jump_2        ;yes - we're gone.
  215.     loop    scan_lpar_1
  216.     dec    di        ;remove final rpar
  217.     mov    ax,offset scan_copy
  218.     jmp    scan_loop
  219. scan_lpar_2:
  220.     inc    cx
  221.     jmp    scan_lpar_1
  222. init_ids_jump_2:
  223.     jmp    init_ids
  224.  
  225. scan_rpar:
  226. ;si -> neutral string
  227. ;di -> active string
  228. ;dx -> previous argument or function pointer.
  229.     dec    di            ;uncopy the ')'
  230.     cmp    si,bp            ;if we scan off the right end, init_ids
  231.     je    init_ids_jump_2
  232.     call    scan_rpar_sub
  233.     call    buffer_check
  234.     jnz    buffers_be_bad
  235.   if timing
  236.     call    readtimer        ;subtract off the start time.
  237.     sub    times[di-2],ax
  238.     inc    counts[di-2]
  239.     push    di
  240.   endif
  241.     call    function_address[di-2]
  242.   if timing
  243.     call    readtimer        ;add in the finishing time
  244.     pop    bx
  245.     add    times[bx-2],ax
  246.   endif
  247.     extrn    buffer_check: near
  248.     call    buffer_check
  249.     jnz    buffers_bad
  250.     mov    bp,data_botbot
  251.     mov    bx,offset scan_xlat_table    ;->translate table
  252.     mov    ax,offset scan_copy
  253.     jmp    scan_loop
  254. buffers_be_bad:
  255.     mov    word ptr buffers_be_msg,ax
  256. buffers_be_bad_1:
  257.     mov    dx,offset buffers_bad_msg
  258.     mov    ah,9
  259.     int    21h
  260.     mov    ah,7
  261.     int    21h
  262.     jmp    buffers_be_bad_1
  263. buffers_bad:
  264.     mov    dx,offset buffers_bad_msg
  265.     mov    ah,9
  266.     int    21h
  267.     mov    ah,7
  268.     int    21h
  269.     jmp    buffers_bad
  270.  
  271. scan_comma:
  272.     mov    al,comma_marker
  273. scan_mark:
  274.     mov    [di-1],al    ;store marker where the character was copied.
  275.     mov    ax,dx        ;get previous pointer
  276.     mov    dx,di        ;save current (will soon be previous)
  277.     stosw
  278.     mov    ax,offset scan_copy
  279. scan_copy_j_1:
  280.     jmp    scan_loop
  281.  
  282. scan_sharp:
  283.     cmp    word ptr [si],'(#'    ;'##(' ?
  284.     je    scan_two_sharps        ;yes.
  285.     cmp    byte ptr [si],'('    ;'#(' ?
  286.     jne    scan_copy_j_1        ;no.
  287.     inc    si
  288.     mov    al,active_marker
  289.     jmp    scan_mark
  290. scan_two_sharps:
  291.     add    si,2
  292.     mov    al,neutral_marker
  293.     jmp    scan_mark
  294.  
  295.     public    abort_fatal
  296. abort_fatal:
  297.     add    sp,22            ;magic number from Z-DOS II, page I.3
  298.     pop    es            ;restore our es and ds.
  299.     push    es
  300.     pop    ds
  301.     mov    sp,offset stackp
  302.     sti                ;enable interrupts again.
  303.     mov    si,offset protected_prompt
  304.     cmp    di,0            ;write protect?
  305.     je    nomem_1
  306.     mov    si,offset fatal_prompt
  307.     jmp    short nomem_1
  308.     public    nomem
  309. nomem:
  310.     esdata
  311.     dsdata
  312.     mov    sp,offset stackp
  313.     mov    si,offset nomem_prompt
  314. nomem_1:
  315.     lodsb
  316.     or    al,al
  317.     je    nomem_2
  318.     mov    dl,al
  319.     mov    ah,2
  320.     int    21h
  321.     jmp    nomem_1
  322. nomem_2:
  323.     jmp    init_ids
  324.  
  325.     extrn    init_ids: near
  326.     extrn    buffer_free: near
  327.  
  328.     public    init_ids_continue, init_ids_first
  329. init_ids_continue:
  330.     cld
  331.     mov    ax,data_botbot        ;get rid of the active string.
  332.     mov    data_bottop,ax
  333.     mov    data_topbot,offset lomem;get rid of the neutral string.
  334.     mov    di,next_ids        ;get the desired idling string.
  335.     mov    si,di            ;save a copy
  336.     mov    next_ids,offset standard_ids    ;reset to ids.
  337.     mov    al,0
  338.     mov    cx,-1
  339.     repne    scasb        ;find the terminating null.
  340.     not    cx
  341.     mov    ax,ds
  342.     call    buffer_free
  343.     mov    di,data_botbot
  344.     sub    di,cx
  345.     dec    di            ;leave room for a sentinel
  346.     mov    data_bottop,di
  347.     rep    movsb
  348.     mov    al,')'            ;use an extra ')' as a sentinel
  349.     stosb
  350. init_ids_first:
  351.     mov    cx,256            ;get at least a little bit of room.
  352.     mov    ax,ds
  353.     call    buffer_free
  354.     mov    si,data_bottop
  355.     mov    di,data_topbot
  356.     mov    dx,0
  357.     mov    bp,data_botbot
  358.     mov    bx,offset scan_xlat_table    ;->translate table
  359.     mov    ax,offset scan_copy
  360.     jmp    scan_loop
  361. init_ids_jump_1:
  362.     jmp    init_ids
  363.  
  364.  
  365.     public    scan_rpar_sub
  366. scan_rpar_sub:
  367. ;store last argument mark
  368.     mov    al,comma_marker
  369.     stosb
  370.     mov    ax,di        ;make final arg -> itself
  371.     stosw
  372. comment @can't use slash***************************************************
  373.     We have a problem here.  Currently, the pointers point backwards
  374. to the previous function/arg.  We want this function's pointers to point
  375. forwards, so we can start at the active/neutral marker and count arguments
  376. forwards.
  377.  
  378.      __ is a pointer, ^ is what it points to.
  379.  
  380.  
  381.     a__SS,__ONE,__TWO,__
  382.       ^    ^    !^    !^
  383.       !   !!    !!    !!
  384.       \___/\____/!    \/
  385.              dx
  386. **********************************************************************@
  387.     mov    fend,di
  388.     mov    data_topbot,di
  389.     sub    di,2        ;make di ->final pointer
  390.     mov    data_bottop,si
  391. scan_rpar_1:
  392.     cmp    dx,0        ;if end of list, we must be running off
  393.     je    init_ids_jump_1    ; the left end (too many rpars)
  394.     mov    bx,dx        ;get previous pointer.
  395.     mov    dx,[bx]        ;get the current pointer [previous pointer].
  396.     mov    [bx],di        ;store the next pointer.
  397.     mov    di,bx        ;save current pointer.
  398. ; bx, di -> current arg/fcn
  399. ; dx -> previous (to the left) arg/fcn
  400.     test    byte ptr -1[bx],function_marker_mask
  401.     jz    scan_rpar_1
  402.     mov    al,-1[bx]
  403.     mov    fcn_save,al        ;remember the type of function.
  404.     mov    prev_fcn,dx
  405.     mov    fbgn,bx
  406.     call    check_breakchar        ;check for a break.
  407.     jnc    got_break_char        ;got it.
  408.     call    trace_invoke        ;destroys al
  409. ;remember that fbgn is really one more than the space taken by the function.
  410.     mov    ax,[bx]            ;get pointer to first arg.
  411.     sub    ax,bx            ;compute length of name
  412.     cmp    ax,2 + mark_overhead    ;two character function name?
  413.     jne    default_to_cl        ;no - must be default.
  414.     mov    ax,2[bx]        ;get function name.
  415.     extrn    store_debug: near
  416.     call    store_debug
  417.     mov    di,offset function_name_table
  418.     mov    cx,offset function_name_length
  419.     repne    scasw
  420.     jne    default_to_cl        ;if not found, default
  421.     sub    di,offset function_name_table
  422.     ret
  423. default_to_cl:
  424.     mov    ax,'d*'
  425.     call    store_debug
  426.     mov    di,0
  427.     ret
  428. got_break_char:
  429.     jmp    init_ids
  430.  
  431. ;return data routines here
  432.  
  433.     public    return_null
  434. return_null:
  435.     mov    cx,0
  436.     call    trace_result    ;destroys al
  437. return_nothing:
  438.     mov    si,data_bottop
  439.     mov    di,fbgn
  440.     dec    di
  441.     mov    dx,prev_fcn
  442.     ret
  443.  
  444.  
  445.     public    return_string
  446. return_string:
  447. ;al=string number to return, bx=>list of strings.
  448.     add    al,al
  449.     mov    ah,0
  450.     add    bx,ax
  451.     mov    si,[bx]
  452.     mov    cx,[bx+2]
  453.     sub    cx,si
  454.     jmp    return_sicx
  455.  
  456.  
  457.     public    return_tos
  458. return_tos:
  459. ;tos -> string, di -> byte after end of string
  460.     pop    si
  461.     mov    cx,di
  462.     sub    cx,si
  463.     jmp    short return_sicx
  464.  
  465.  
  466.     public    make_active
  467. make_active:
  468. ;force a function's return value to be active.
  469. ;return zr if the function already was active.
  470.     cmp    fcn_save,active_marker
  471.     mov    fcn_save,active_marker
  472.     ret
  473.  
  474.  
  475.     public    return_arg_active
  476. return_arg_active:
  477.     mov    fcn_save,active_marker
  478. ;falls through
  479. ;
  480.     public    return_arg
  481. return_arg:
  482. ;enter with cx = number of arg to return.
  483.     call    getarg
  484. ;fall through to return_sicx
  485.  
  486.  
  487.     public    return_sicx
  488. return_sicx:
  489. ;si -> string, cx = count.
  490.     cmp    fcn_save,active_marker    ;active or neutral
  491.     jne    return_neutral
  492. ;    jmp    return_active        ;fall through!
  493.  
  494.  
  495.     public    return_active
  496. return_active:
  497. ;we need to move [si] count cx
  498. ; to [data_bottop-cx] through [data_bottop-1] reverse
  499. ;Then we return si = [data_bottop-cx], di=fbgn-1
  500.     call    trace_result    ;destroys al
  501.     jcxz    return_nothing    ;quick check for 0 chars.
  502.     mov    di,data_bottop
  503.     dec    di
  504.     add    si,cx        ;point si to end of string + 1.
  505.     dec    si        ;remember, it's postdecrement.
  506.     std            ;reverse move
  507.     rep    movsb
  508.     cld            ;everybody assumes it's cleared.
  509.     inc    di        ;make di -> last byte moved.
  510.     mov    si,di        ;si -> what we just moved.
  511.     mov    di,fbgn        ;remove previous function.
  512.     dec    di
  513.     mov    dx,prev_fcn
  514.     ret
  515.  
  516.     public    return_neutral
  517. return_neutral:
  518. ;we need to move [si] count cx
  519. ; to [fbgn-1] through [fbgn-1] - (cx - 1)
  520. ;Then we return si=data_bottop, di=[fbgn-1] - cx
  521.     call    trace_result    ;destroys al
  522.     jcxz    return_nothing    ;quick check for 0 chars.
  523.     mov    di,fbgn
  524.     dec    di
  525.     cmp    di,si        ;is it there already?
  526.     je    return_neutral_1    ;yes, save some time.
  527.     rep    movsb        ;put it there.
  528. return_neutral_1:
  529. ;tricky time!  If we performed the movsb, cx is zero, so we're doing
  530. ;nothing.  If we took the jump to return_neutral_1, cx is the proper
  531. ;count, so di will point to the right place.
  532.     add    di,cx
  533.     mov    si,data_bottop
  534.     mov    dx,prev_fcn
  535.     ret
  536.  
  537.  
  538.     extrn    trace_result: near
  539.     extrn    trace_invoke: near
  540.  
  541. ;utility subroutines
  542.  
  543.  
  544.     extrn    check_breakchar: near
  545.  
  546.  
  547.     public    getarg1, getarg
  548. getarg1:    mov    cx,1
  549.  
  550. ;fall through to getarg
  551.  
  552. getarg:
  553.  
  554. ;enter with cx = number of argument to get.
  555. ;exit with si -> argument, cx=length of argument.
  556.  
  557. comment /****************************************************************
  558.  
  559. The pointer after the last supplied argument points to itself, which allows
  560. us to loop at getarg_loop until we think that we have found the argument.  Of
  561. course, if that argument has not been supplied, all that we've done is to chase
  562. the last pointer a few times.  As an aside, had you ever noticed that when the
  563. amount of comments exceeds the amount of code, the code is likely to be
  564. confusing?  Well, this code is probably confusing.
  565.  
  566. *************************************************************************/
  567.     mov    si,fbgn
  568.     jcxz    getarg_2    ;skip loop if count is zero.
  569. getarg_loop:
  570.     mov    si,[si]        ;get our argument
  571.     loop    getarg_loop
  572. getarg_2:
  573.     mov    cx,[si]        ;get cx=next argument
  574.     sub    cx,si        ;get cx=length of our argument
  575.     jcxz    getarg_1    ;in case we ran into fend, it doesn't matter what si -> to.
  576.     sub    cx,mark_overhead
  577.     add    si,mark_overhead-1    ;make si-> text of argument.
  578. getarg_1:
  579.     ret
  580.  
  581.  
  582.   if timing
  583. readtimer:
  584. ;exit with dx:ax set to the time since the last tick.
  585.     cmp    counting,0
  586.     je    readtimer_2
  587.  
  588.     mov    al,00h            ;Latch timer 0
  589.     out    043h,al
  590.     in    al,040h            ;Counter --> bx*/
  591.     mov    ah,al            ;LSB in BL
  592.     in    al,040h
  593.     xchg    ah,al
  594.     not    ax            ;Need ascending counter
  595.  
  596. readtimer_2:
  597.     ret
  598.   endif
  599.  
  600.  
  601. code    ends
  602.  
  603.     end
  604.  
  605.